<template>
  <div class="content" id="box">
    <canvas
      id="canvas"
      :width="width"
      :height="height"
      :style="{ backgroundColor: backgroundColor }"
      @mousemove="move"
      @mouseup="over"
      @mouseenter="enter"
      @mouseleave="leave"
      @click="clickOne"
    ></canvas>

    <div class="preview" v-show="showMask" @click="exitPreview">
      <img :src="url" alt="图片无法显示" />
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Watch } from "vue-property-decorator";
import _ from "lodash";
import { saveAs } from "file-saver";

import bus from "@/utils/eventBus";
import isText from "@/utils/isText";
import isEdge from "@/utils/isEdge";
import createCanvas from "@/utils/createCanvas";
import getTextHeight from "@/utils/getTextHeight";
import autoFit from "@/utils/autoFit";

import ITextArea from "@/interface/ITextArea";
import ITextCanvas from "@/interface/canvas/ITextCanvas";
import IRectCanvas from "@/interface/canvas/IRectCanvas";

import bgColorModule from "@/store/modules/backgroundColor";
import canvasListModule from "@/store/modules/canvas";

@Component({
  components: {},
})
export default class Emain_content extends Vue {
  width = 200; //canvas显示宽度
  height = 200;
  flag = false; //是否显示文字的边框
  backgroundColor = "";
  isMove = false; //是否开启拖拽，true开启，false反之
  clickCount = 0; //点击次数，用来修复点击一次之后一直能拖拽的bug
  moveText: ITextArea = {
    //记录移动区域的文字和坐标
    isValue: false,
  };

  url = "";
  showMask = false; //是否开启全屏预览

  trueW = 0; //canvas真实宽度
  trueH = 0;
  ratio = "100.0%"; //缩放比例

  timer1 = 0;
  timer2 = 1;

  canvas = {};

  cxt = {};

  @Watch("ratio")
  handleRatio(ratio: string): void {
    bus.$emit("ratio", ratio);
  }

  created(): void {
    this.trueW = this.width;
    this.trueH = this.height;
    this.backgroundColor = bgColorModule.getbgcolor;
    bus.$on("downloadImage", () => {
      this.$nextTick(() => {
        const canvas2 = createCanvas(
          this.width,
          this.height,
          this.backgroundColor
        );

        interface value {
          value: string;
          action: string;
        }

        //导出为图片
        canvas2.toBlob((blob) => {
          this.$prompt("请输入文件名", "提示", {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
          })
            .then((res) => {
              const data = res as value;
              saveAs(blob as Blob, data.value + ".png");

              this.$message({
                type: "success",
                message: "导出成功",
              });
            })
            .catch(() => {
              this.$message({
                type: "info",
                message: "取消输入",
              });
            });
        });
      });
    });
  }

  mounted(): void {
    this.init();

    const el = document.getElementById("box");

    const rect = el?.getBoundingClientRect();

    const w = rect?.width as number;
    const h = rect?.height as number;

    bus.$on("canvasHeight", (height: number): void => {
      this.trueH = height;

      console.log(this.trueH, this.trueW);
      const res = autoFit(this.trueW, height, w, h);

      this.width = res.width;
      this.height = res.height;
      this.ratio = res.zoom;

      const loading = this.$loading({
        lock: true,
        text: "Loading",
        spinner: "el-icon-loading",
        background: "rgba(0, 0, 0, 0.7)",
      });

      //点击两次canvas，修复修改宽高之后canvas内容丢失的bug
      const canvas = document.getElementById("canvas") as HTMLCanvasElement;

      canvas.click();

      this.timer1 = setTimeout(() => {
        canvas.click();
        loading.close();
      }, 500);
    });

    bus.$on("canvasWidth", (width: number): void => {
      this.trueW = width;
      const res = autoFit(width, this.trueH, w, h);

      console.log(this.trueH, this.trueW);

      this.width = res.width;
      this.height = res.height;
      this.ratio = res.zoom;

      const loading = this.$loading({
        lock: true,
        text: "Loading",
        spinner: "el-icon-loading",
        background: "rgba(0, 0, 0, 0.7)",
      });

      //点击两次canvas，修复修改宽高之后canvas内容丢失的bug
      const canvas = document.getElementById("canvas") as HTMLCanvasElement;

      canvas.click();

      this.timer2 = setTimeout(() => {
        canvas.click();
        loading.close();
      }, 500);
    });

    bus.$on("changeColor", (color: string): void => {
      console.log(color);
      this.backgroundColor = bgColorModule.getbgcolor;
    });

    bus.$on("preview", () => {
      const canvas2 = createCanvas(
        this.width,
        this.height,
        this.backgroundColor
      );

      this.url = canvas2.toDataURL();
      this.showMask = true;
    });
  }

  beforeDestroy(): void {
    clearTimeout(this.timer1);
    clearTimeout(this.timer2);
  }

  exitPreview(): void {
    //退出全屏预览
    this.showMask = false;
  }

  move(event: MouseEvent): void {
    const area: ITextArea = isText(
      this.cxt as CanvasRenderingContext2D,
      event.offsetX,
      event.offsetY
    );

    if (area.isValue) {
      this.moveText = _.cloneDeep(area);
    }

    if (this.isMove) {
      // 开启拖拽
      const ex = event.offsetX;
      const ey = event.offsetY;

      const cxt = this.cxt as CanvasRenderingContext2D;
      const canvas = this.canvas as HTMLCanvasElement;
      //拷贝canvas数据
      const list = _.cloneDeep(canvasListModule.getcanvasList);

      //清空vuex中canvas模块的所有数据
      canvasListModule.clearCanvasList();

      for (let i = 0; i < list.length; i++) {
        if (list[i].type == "text") {
          const item = list[i] as ITextCanvas;
          const len = cxt.measureText(item.text).width;

          if (
            item.text == this.moveText.text &&
            item.x == this.moveText.x &&
            item.y == this.moveText.y &&
            isEdge(ex, ey, len, this.width, this.height)
          ) {
            item.x = ex;
            item.y = ey;
          }
        }
      }

      //清空canvas
      cxt.clearRect(0, 0, canvas.width, canvas.height);

      for (let i = 0; i < list.length; i++) {
        if (list[i].type == "text") {
          const cnt = list[i] as ITextCanvas;
          this.createText(cnt.x, cnt.y, cnt.text as string);
        }
      }
    }
  }

  over(): void {
    this.isMove = false;
  }

  enter(): void {
    this.isMove = false;
  }

  leave(): void {
    this.isMove = false;
  }

  clickOne(event: PointerEvent): void {
    const area: ITextArea = isText(
      this.cxt as CanvasRenderingContext2D,
      event.offsetX,
      event.offsetY
    );

    if (area.isValue) {
      this.moveText = _.cloneDeep(area);
    }

    if (this.clickCount == 0) {
      this.isMove = true;
      this.clickCount = 1;
    } else if (this.clickCount == 1) {
      this.isMove = false;
      this.clickCount = 0;
    } else {
      this.clickCount == 1;
    }

    if (!this.flag) {
      const list = _.cloneDeep(canvasListModule.getcanvasList);

      for (let i = 0; i < list.length; i++) {
        if (list[i].type == "text") {
          const cnt = list[i] as ITextCanvas;
          this.createRect(cnt.x, cnt.y, cnt.text as string);
        }
      }
      //完成绘制
      this.flag = true;
    } else {
      const cxt = this.cxt as CanvasRenderingContext2D;
      const canvas = this.canvas as HTMLCanvasElement;
      //拷贝canvas数据
      const list = _.cloneDeep(canvasListModule.getcanvasList);
      //清空vuex中canvas模块的所有数据
      canvasListModule.clearCanvasList();
      //清空canvas
      cxt.clearRect(0, 0, canvas.width, canvas.height);

      for (let i = 0; i < list.length; i++) {
        if (list[i].type == "text") {
          const cnt = list[i] as ITextCanvas;
          this.createText(cnt.x, cnt.y, cnt.text as string);
        }
      }

      console.log(canvasListModule.getcanvasList);

      this.flag = false;
    }
  }

  init(): void {
    const canvas = document.getElementById("canvas") as HTMLCanvasElement;
    const cxt = canvas.getContext("2d") as CanvasRenderingContext2D;

    this.canvas = canvas;
    this.cxt = cxt;

    this.createText(50, 90, "hello world");
    this.createText(150, 120, "world");
  }

  createText(x: number, y: number, text: string): void {
    const cxt = this.cxt as CanvasRenderingContext2D;
    cxt.strokeStyle = "red";
    cxt.strokeText(text, x, y);

    const data: ITextCanvas = {
      type: "text",
      text,
      x,
      y,
      font: "bold 14px 楷体",
    };

    //上传文字数据到vuex
    canvasListModule.changecanvasList(data);
  }

  createRect(x: number, y: number, text: string): void {
    const cxt = this.cxt as CanvasRenderingContext2D;
    const len = cxt.measureText(text).width;
    const height = getTextHeight("14px");
    cxt.strokeStyle = "blue";
    cxt.strokeRect(x - 15, y - height / 2 - 4, len + 30, height);

    const data: IRectCanvas = {
      type: "rect",
      x: x - 15,
      y: y - height / 2 - 4,
      width: len + 30,
      height: height,
    };

    canvasListModule.changecanvasList(data);
  }
}
</script>

<style lang="scss" scoped>
.content {
  width: 100%;
  box-sizing: border-box;
  flex: 1;
  background-color: gray;
  display: flex;
  justify-content: center;
  align-items: center;

  .preview {
    width: 100%;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
</style>
